﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Framework.Common.HashDFA
{
    public static class SensitiveWordsHelper
    {
        static readonly DFADict<char> dict;

        static SensitiveWordsHelper()
        {
            dict = new DFADict<char>();
        }
        /// <summary>
        /// 初始换字典库
        /// </summary>
        /// <param name="fillDict"></param>
        public static void InitDict(Func<IEnumerable<string>> fillDict)
        {
            if (fillDict != null)
            {
                var words = fillDict();
                foreach (var word in words)
                {
                    dict.Add(word.ToCharArray());
                }
            }
        }
        /// <summary>
        /// 是否包含关键字
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool HasSensitiveWords(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return false;
            }
            return dict.Contains(input.ToCharArray());
        }
        /// <summary>
        /// 获取敏感字的位置
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static IEnumerable<StartEnd> GetSensitiveWordsPosition(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return null;
            }
            return GetSensitiveWordsPosition(input.ToCharArray());
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="chars"></param>
        /// <returns></returns>
        public static IEnumerable<StartEnd> GetSensitiveWordsPosition(char[] chars)
        {
            return dict.Match(chars);
        }

        /// <summary>
        /// 获取敏感字的位置
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static IEnumerable<string> GetSensitiveWords(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                yield break;
            }
            char[] charArrays = input.ToCharArray();
            var positions = GetSensitiveWordsPosition(charArrays);
            if (positions != null)
            {
                foreach (var pos in positions)
                {
                    yield return new string(charArrays.Take(pos.End + 1).Skip(pos.Start).ToArray());
                }
            }
        }
        const string defaultChars = "***";
        /// <summary>
        /// 用***替换敏感字符
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string FilterSensitiveWords(string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return input;
            }
            char[] charArrays = input.ToCharArray();
            var positions = GetSensitiveWordsPosition(charArrays);
            if (positions != null && positions.Count() > 0)
            {
                StringBuilder sb = new StringBuilder();
                int offset = -1;
                var tmp = positions.GetEnumerator();
                while (tmp.MoveNext())
                {
                    for (int i = offset + 1; i < tmp.Current.Start; i++)
                    {
                        sb.Append(charArrays[i]);
                    }
                    sb.Append(defaultChars);
                    offset = tmp.Current.End;
                }
                for (int i = offset + 1; i < charArrays.Length; i++)
                {
                    sb.Append(charArrays[i]);
                }
                return sb.ToString();
            }
            else
            {
                return input;
            }
        }
        /// <summary>
        /// 将敏感字替换成字典中对应的字符
        /// </summary>
        /// <param name="input"></param>
        /// <param name="replaceDict"></param>
        /// <returns></returns>
        public static string FilterSensitiveWords(string input, IDictionary<string, string> replaceDict)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return input;
            }
            char[] charArrays = input.ToCharArray();
            var positions = GetSensitiveWordsPosition(charArrays);
            if (positions != null && positions.Any())
            {
                StringBuilder sb = new StringBuilder();
                int offset = -1;
                var tmp = positions.GetEnumerator();
                while (tmp.MoveNext())
                {
                    for (int i = offset + 1; i < tmp.Current.Start; i++)
                    {
                        sb.Append(charArrays[i]);
                    }

                    #region 替换处理
                    string badWord = new string(charArrays.Take(tmp.Current.End + 1).Skip(tmp.Current.Start).ToArray());
                    string replaceToString;
                    if (replaceDict.TryGetValue(badWord, out replaceToString))
                    {
                        sb.Append(replaceToString);
                    }
                    else
                    {
                        sb.Append(defaultChars);
                    }
                    #endregion

                    offset = tmp.Current.End;
                }
                for (int i = offset + 1; i < charArrays.Length; i++)
                {
                    sb.Append(charArrays[i]);
                }
                return sb.ToString();
            }
            else
            {
                return input;
            }
        }

    }
}
